#include "IR.h"
#include "sys/ZG_system.h"
#include "FreeRTOS.h"
#include "task.h"
#include "s907x_zg_config.h"
#include "timers.h"
#include "hal_gpio.h"
#include "hal_timer.h"

uint8_t ir_repeat =  0;

static  timer_hdl_t tim_hdl;


typedef struct ir_st_
{
 
    u8  buf[4];
    u8  buf_id;
    u8 key;      
    u16 capture_idx;
    u16 state;
    u16 addr; 
    sema_t cap_down;
    int rep_cnt;  
    int rep_cnt_his;
    int init_short_press;
    int short_press;
    TimerHandle_t monitor_timer; 
}ir_t;

static ir_t g_ir;
#define IR_DATA(x)    (x*2ul) 


static u8 rebuild_pos(u8 data)
{
     u8 ret = 0;
     u8 temp = 0;
     
     ret = data & 0x01;// 0000 0001
     ret = ret >> 0;
     temp |= ret;
     temp = temp << 1;
     
     ret = data & 0x02;// 0000 0010
     ret = ret >> 1;
     temp |= ret;
     temp = temp << 1;
     
     ret = data & 0x04;//0000 0100
     ret = ret >> 2;
     temp |= ret;
     temp = temp << 1;
     
     ret = data & 0x08; //0000 1000
     ret = ret >> 3;
     temp |= ret;
     temp = temp << 1;
     
     ret = data & 0x10; //0001 0000
     ret = ret >> 4;
     temp |= ret;
     temp = temp << 1;
     
     ret = data & 0x20;//0010 0000
     ret = ret >> 5;
     temp |= ret;
     temp = temp << 1;
     
     ret = data & 0x40;//0100 0000
     ret = ret >> 6;
     temp |= ret;
     temp = temp << 1;
     
     ret = data & 0x80;//1000 0000
     ret = ret >> 7;
     temp |= ret;
     
     return temp;
   
}

static void build_key(void)
{
    g_ir.addr = BUILD_UINT16(rebuild_pos(g_ir.buf[1]), rebuild_pos(g_ir.buf[0]));
	
    g_ir.key = rebuild_pos(g_ir.buf[2]);
	
}


unsigned int get_remote_addr()      
{
	//printf("ir addr = %x \n", g_ir.addr);
    return g_ir.addr;
}

unsigned char GET_IR_Repeat()
{
	
   return g_ir.rep_cnt;
}

static void ir_cap_stop(int notify);

int get_remote_key(unsigned char *key,unsigned int time)
{
    int ret;

    ret = wl_wait_sema(&g_ir.cap_down, time);     
    if(ret) {
		
        build_key();
		
//        g_ir.state = IR_NEC_STATE_IDLE;     
//        g_ir.capture_stop = TRUE;
//        g_ir.capture_idx = 0;
//        g_ir.buf_id = 0;

//	printf("ir key = %x %d %d \n", g_ir.key, g_ir.state, g_ir.buf_id);
#if 0       
        printf_arrary((u8*)test_cap, sizeof(test_cap), ARY_U16, 0);
        printf_arrary((u8*)test_cap_state, sizeof(test_cap_state), ARY_U16, 0);
#endif   
        *key = g_ir.key;
    
    }
    return ret;
}


static void ir_recv_data(u8 zero)
{
    int pos  = g_ir.buf_id / IR_NEC_BIT_NUM;

    if(pos >= sizeof(g_ir.buf)) {
        return;
    }

    g_ir.buf[pos] = g_ir.buf[pos] << 1;
    g_ir.buf[pos] += zero;
    g_ir.buf_id ++;
}

static void ir_cap_stop(int notify)
{

    g_ir.state = IR_NEC_STATE_IDLE;     
    g_ir.short_press = FALSE;
    g_ir.rep_cnt_his  = g_ir.rep_cnt = 0;
    g_ir.capture_idx = 0;
    g_ir.buf_id = 0;
   
    if(notify) {      
        wl_send_sema_fromisr(&g_ir.cap_down);
    }    
    
}


 
static void ir_monitor_cb(void *ctx)
{
	
	if(g_ir.short_press) {
		if(g_ir.rep_cnt_his != g_ir.rep_cnt) {
		   g_ir.rep_cnt_his = g_ir.rep_cnt;
		   //printf("long!%d:%d\n", g_ir.rep_cnt_his, g_ir.rep_cnt);
		} else {
		   ir_cap_stop(FALSE);
		   //printf("shot!\n");
		}
	}
}

static void ir_hsm(u16 temp)
{
    u32 val = IR_DATA(temp);
   
    switch(g_ir.state) 
    {
        case IR_NEC_STATE_IDLE:
            if(val > (IR_NEC_TM_PRE_US - IR_NEC_MAGIN_US * 2) && val < (IR_NEC_TM_PRE_US + IR_NEC_MAGIN_US * 2)) {
                g_ir.state = IR_NEC_STATE_CMD;
                g_ir.buf_id = 0;
            }  else if(g_ir.init_short_press && (val > IR_NEC_REP_TM1_US * 45  &&  val < IR_NEC_REP_TM1_US * 55)){  //90 ~ 110
				g_ir.rep_cnt_his = g_ir.rep_cnt = 0;
				g_ir.short_press = TRUE;
                g_ir.state = IR_NEC_STATE_REPEAT_1;
            }
            break;
        case IR_NEC_STATE_CMD:
            if(val > (IR_NEC_D0_TM_US - IR_NEC_MAGIN_US) && val < (IR_NEC_D0_TM_US + IR_NEC_MAGIN_US)) {
                ir_recv_data(0);
            } else if(val > (IR_NEC_D1_TM_US - IR_NEC_MAGIN_US) && val < (IR_NEC_D1_TM_US + IR_NEC_MAGIN_US)) {
                ir_recv_data(1);
            } else {
                ir_cap_stop(FALSE);
            }
            if(g_ir.buf_id >= 32) {
                g_ir.state = IR_NEC_STATE_REPEAT_1;
                g_ir.short_press = TRUE;
				if(!g_ir.init_short_press) {
					g_ir.init_short_press = TRUE;
				}
				g_ir.rep_cnt_his = g_ir.rep_cnt = 0;
                wl_send_sema_fromisr(&g_ir.cap_down);
            } 
            break;
        case IR_NEC_STATE_REPEAT_2:  //90000 ~ 110000  90~110
            if(val > IR_NEC_REP_TM1_US * 45  &&  val < IR_NEC_REP_TM1_US * 55){
                g_ir.state = IR_NEC_STATE_REPEAT_1;
              
                wl_send_sema_fromisr(&g_ir.cap_down);
   
            }else{  
                //for normal key pressed
                ir_cap_stop(FALSE);
            }
            break; 
        case IR_NEC_STATE_REPEAT_1:       //.9000 ~ 12000
             if(val < (IR_NEC_REP_TM1_US * 6+ IR_NEC_MAGIN_US) && val > (IR_NEC_REP_TM2_US * 8  - IR_NEC_MAGIN_US)){
                //for repeat key pressed
                g_ir.state = IR_NEC_STATE_REPEAT_2;
                g_ir.rep_cnt++;
              
               
            }else{

            }
            break;
        default:
            //stop
            break;
    }
}



static void timer_capture_gpio7(void *context)
{
     timer_hdl_t *tim = context;
     static u16 cap_0;
     static u16 cap_1;
     u16 temp;
   


     if(g_ir.capture_idx % 2 == 0) {
        cap_0 = s907x_hal_timer_get_counter(tim);
        if(g_ir.capture_idx > 1) {
            temp = ((cap_0 >= cap_1) ? (cap_0 - cap_1) : (0xFFFF - cap_1 + cap_0));
        }
     } else {
        cap_1 = s907x_hal_timer_get_counter(tim);
        temp = ((cap_1 >= cap_0) ? (cap_1 - cap_0) : (0xFFFF - cap_0 + cap_1));
     }
     ir_hsm(temp);
     g_ir.capture_idx ++;
      


}




void ir_init(void)
{
    timer_hdl_t *tim = &tim_hdl;
    tim->config.idx = TIM_CAP;


    memset(&g_ir, 0, sizeof(g_ir));
    
    wl_init_sema(&g_ir.cap_down, 0, sema_counter);

    s907x_hal_timer_stop(tim);
    
    tim->config.prescaler = 79;

    tim->config.period = 65535; 
    tim->config.int_enable = 0;
    //set user callback
    tim->it.basic_user_cb.func = NULL;
    tim->it.basic_user_cb.context = tim;

    s907x_hal_timer_base_init(tim);
    s907x_hal_timer_start_base(tim);

    gpio_init_t init;
    init.mode = GPIO_MODE_INT_FALLING;
    init.pull = GPIO_PULLUP;
    
    s907x_hal_gpio_init(GPIO7, &init);
    s907x_hal_gpio_it_start( GPIO7, timer_capture_gpio7, tim);   
    
	printf("ir create timer\n"); 
	
    g_ir.monitor_timer = xTimerCreate("ir timer", 150, pdTRUE,(void *)0, ir_monitor_cb);
	xTimerStart(g_ir.monitor_timer, 0);
/*	
    tim = &tim_repeat_hdl;
    tim->config.idx = TIM3;
    tim->config.prescaler = 0x0;
    tim->config.period = 6399; //5hz 
    tim->config.int_enable = 1;
      //set user callback
    tim->it.basic_user_cb.func = ir_repeat_check_isr;
    tim->it.basic_user_cb.context = tim;

    s907x_hal_timer_base_init(tim);
*/
}


static void ir_entry(void)
{
    ir_init();
    //wl_create_thread("ir thread", 512, 2, (thread_func_t)ir_task, NULL);
}

void IR_Init()
{
    ir_entry();
}




